package org.example.demo3.service.impl;

import lombok.RequiredArgsConstructor;
import org.example.demo3.dto.LoginDTO;
import org.example.demo3.dto.LoginResponseDTO;
import org.example.demo3.dto.RegisterDTO;
import org.example.demo3.dto.RegisterResponseDTO;
import org.example.demo3.dto.ResetPasswordDTO;
import org.example.demo3.dto.SendResetCodeDTO;
import org.example.demo3.dto.TokenDTO;
import org.example.demo3.dto.UpdateProfileDTO;
import org.example.demo3.enity.User;
import org.example.demo3.enity.Token;
import org.example.demo3.enity.VerificationCode;
import org.example.demo3.mapper.UserMapper;
import org.example.demo3.mapper.TokenMapper;
import org.example.demo3.mapper.VerificationCodeMapper;
import org.example.demo3.service.EmailService;
import org.example.demo3.service.UserService;
import org.example.demo3.untils.JwtUtil;
import org.example.demo3.untils.PasswordUtil;
import org.example.demo3.vo.UserInfoVO;
import org.example.demo3.vo.UserVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.Random;
import java.util.regex.Pattern;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    // 用户名验证：6-20位纯数字
    private static final Pattern USERNAME_PATTERN = Pattern.compile("^\\d{6,20}$");
    
    // 密码验证：8-20位，必须包含数字和字母
    private static final Pattern PASSWORD_PATTERN = Pattern.compile("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,20}$");
    
    // 邮箱验证
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$");
    
    // 设置默认头像URL
    private static final String DEFAULT_AVATAR = "default.jpg";

    // 验证码类型：重置密码
    private static final String VERIFICATION_TYPE_RESET_PASSWORD = "RESET_PASSWORD";
    
    // 验证码有效期（分钟）
    private static final int VERIFICATION_CODE_EXPIRE_MINUTES = 15;

    // 用户Mapper
    private final UserMapper userMapper;
    // Token Mapper
    private final TokenMapper tokenMapper;
    // 验证码Mapper
    private final VerificationCodeMapper verificationCodeMapper;
    // JWT工具类
    private final JwtUtil jwtUtil;
    // 密码工具类
    private final PasswordUtil passwordUtil;
    // 邮件服务
    private final EmailService emailService;

    @Override
    @Transactional
    public LoginResponseDTO login(LoginDTO loginDTO) {
        // 1. 验证用户名和密码
        Optional<User> userOpt = userMapper.findByUsername(loginDTO.getUsername());
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }

        User user = userOpt.get();
        if (!passwordUtil.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        if (user.getStatus() != 1) {
            throw new RuntimeException("账号已被禁用");
        }

        // 2. 生成新的token
        String accessToken = jwtUtil.generateAccessToken(user.getId());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId());

        // 3. 保存token到数据库
        Token token = new Token();
        token.setUserId(user.getId());
        token.setAccessToken(accessToken);
        token.setRefreshToken(refreshToken);
        token.setCreatedAt(LocalDateTime.now());
        token.setExpiresAt(LocalDateTime.now().plusHours(24)); // token有效期24小时
        token.setStatus(1);

        // 先使旧token失效
        tokenMapper.invalidate(user.getId());
        // 保存新token
        tokenMapper.insert(token);

        // 4. 返回LoginResponseDTO，包含token信息和用户基本信息
        LoginResponseDTO responseDTO = new LoginResponseDTO();
        // 设置token信息
        responseDTO.setAccessToken(accessToken);
        responseDTO.setRefreshToken(refreshToken);
        responseDTO.setExpiresIn(24 * 60 * 60L); // 24小时的秒数
        
        // 设置用户基本信息
        responseDTO.setUserId(user.getId());
        responseDTO.setAvatar(user.getAvatar());

        return responseDTO;
    }

    @Override
    public UserVO getUserVO(Long userId) {
        Optional<User> userOpt = userMapper.findById(userId);
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }

        User user = userOpt.get();
        UserVO userVO = new UserVO();
        userVO.setUserId(user.getId());
        userVO.setAvatar(user.getAvatar());

        return userVO;
    }

    @Override
    public UserInfoVO getUserInfoVO(Long userId) {
        Optional<User> userOpt = userMapper.findById(userId);
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }

        User user = userOpt.get();
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setUserId(user.getId());
        userInfoVO.setNickname(user.getNickname());
        userInfoVO.setEmail(user.getEmail());
        userInfoVO.setAvatar(user.getAvatar());
        userInfoVO.setGender(user.getGender());

        return userInfoVO;
    }

    @Override
    @Transactional
    public TokenDTO refreshToken(String refreshToken) {

        Long userId = jwtUtil.validateRefreshToken(refreshToken);
       // if (userId == null) {
      //      throw new RuntimeException("无效的刷新令牌");
      //  }

        // 2. 生成新的token
        String newAccessToken = jwtUtil.generateAccessToken(userId);
        String newRefreshToken = jwtUtil.generateRefreshToken(userId);

        // 3. 更新数据库中的token
        Optional<Token> tokenOpt = tokenMapper.findByUserId(userId);
     //   if (tokenOpt.isEmpty()) {
       //     throw new RuntimeException("Token不存在");
       // }

        Token token = tokenOpt.get();
        token.setAccessToken(newAccessToken);
        token.setRefreshToken(newRefreshToken);
        token.setExpiresAt(LocalDateTime.now().plusHours(24));
        tokenMapper.update(token);

        // 4. 返回新的TokenDTO
        TokenDTO tokenDTO = new TokenDTO();
        tokenDTO.setAccessToken(newAccessToken);
        tokenDTO.setRefreshToken(newRefreshToken);
        tokenDTO.setExpiresIn(24 * 60 * 60L);

        return tokenDTO;
    }

    @Override
    @Transactional
    public RegisterResponseDTO register(RegisterDTO registerDTO) {
        // 1. 参数校验
        validateRegisterParams(registerDTO);
        
        // 2. 唯一性检查
        checkUniqueness(registerDTO.getUsername(), registerDTO.getEmail());
        
        // 3. 创建用户
        User user = createUser(registerDTO);
        
        // 4. 保存用户
        userMapper.insert(user);
        
        // 5. 返回结果
        RegisterResponseDTO responseDTO = new RegisterResponseDTO();
        responseDTO.setUserId(user.getId());
        responseDTO.setAvatar(user.getAvatar());
        
        return responseDTO;
    }
    
    /**
     * 验证注册参数
     */
    private void validateRegisterParams(RegisterDTO registerDTO) {
        // 验证用户名
        if (registerDTO.getUsername() == null || !USERNAME_PATTERN.matcher(registerDTO.getUsername()).matches()) {
            throw new RuntimeException("用户名格式错误，必须为6-20位纯数字");
        }
        
        // 验证密码
        if (registerDTO.getPassword() == null || !PASSWORD_PATTERN.matcher(registerDTO.getPassword()).matches()) {
            throw new RuntimeException("密码格式错误，必须为8-20位，且包含数字和字母");
        }
        
        // 验证昵称
        if (registerDTO.getNickname() == null || registerDTO.getNickname().length() < 1 || registerDTO.getNickname().length() > 10) {
            throw new RuntimeException("昵称长度必须在1-10个字符之间");
        }
        
        // 验证邮箱
        if (registerDTO.getEmail() == null || !EMAIL_PATTERN.matcher(registerDTO.getEmail()).matches()) {
            throw new RuntimeException("邮箱格式错误");
        }
        
        // 验证性别（如果提供）
        if (registerDTO.getGender() != null && (registerDTO.getGender() < 0 || registerDTO.getGender() > 2)) {
            throw new RuntimeException("性别参数错误，必须为0-2之间的整数");
        }
    }
    
    /**
     * 检查用户名和邮箱的唯一性
     */
    private void checkUniqueness(String username, String email) {
        // 检查用户名是否已存在
        if (userMapper.existsByUsername(username)) {
            throw new RuntimeException("用户名已被使用");
        }
        
        // 检查邮箱是否已存在
        if (userMapper.existsByEmail(email)) {
            throw new RuntimeException("邮箱已被注册");
        }
    }
    
    /**
     * 创建用户实体
     */
    private User createUser(RegisterDTO registerDTO) {
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        // 密码加密
        user.setPassword(passwordUtil.encode(registerDTO.getPassword()));
        user.setNickname(registerDTO.getNickname());
        user.setEmail(registerDTO.getEmail());
        // 设置默认头像
        user.setAvatar(DEFAULT_AVATAR);
        // 设置性别，如果未提供则默认为0（未知）
        user.setGender(registerDTO.getGender() != null ? registerDTO.getGender() : 0);
        // 设置创建时间和更新时间
        LocalDateTime now = LocalDateTime.now();
        user.setCreateTime(now);
        user.setUpdateTime(now);
        // 设置用户状态为正常(1)
        user.setStatus(1);
        
        return user;
    }

    @Override
    @Transactional
    public UserInfoVO updateProfile(Long userId, UpdateProfileDTO updateProfileDTO) {
        // 1. 参数校验
        validateUpdateProfileParams(updateProfileDTO);
        
        // 2. 获取当前用户信息
        Optional<User> userOpt = userMapper.findById(userId);
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }
        User user = userOpt.get();
        
        // 3. 检查邮箱唯一性
        if (updateProfileDTO.getEmail() != null && 
            !updateProfileDTO.getEmail().equals(user.getEmail()) && 
            userMapper.existsByEmailAndIdNot(updateProfileDTO.getEmail(), userId)) {
            throw new RuntimeException("邮箱已被其他用户使用");
        }
        
        // 4. 更新用户信息
        boolean needUpdate = false;
        
        if (updateProfileDTO.getNickname() != null) {
            user.setNickname(updateProfileDTO.getNickname());
            needUpdate = true;
        }
        
        if (updateProfileDTO.getEmail() != null) {
            user.setEmail(updateProfileDTO.getEmail());
            needUpdate = true;
        }
        
        if (updateProfileDTO.getGender() != null) {
            user.setGender(updateProfileDTO.getGender());
            needUpdate = true;
        }
        
        if (updateProfileDTO.getAvatar() != null) {
            user.setAvatar(updateProfileDTO.getAvatar());
            needUpdate = true;
        }
        
        // 5. 如果有字段更新，则更新数据库
        if (needUpdate) {
            user.setUpdateTime(LocalDateTime.now());
            userMapper.update(user);
        }
        
        // 6. 返回更新后的用户信息
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setUserId(user.getId());
        userInfoVO.setUsername(user.getUsername());
        userInfoVO.setNickname(user.getNickname());
        userInfoVO.setEmail(user.getEmail());
        userInfoVO.setAvatar(user.getAvatar());
        userInfoVO.setGender(user.getGender());
        
        return userInfoVO;
    }
    
    /**
     * 验证更新用户信息参数
     */
    private void validateUpdateProfileParams(UpdateProfileDTO updateProfileDTO) {
        // 验证昵称
        if (updateProfileDTO.getNickname() != null && 
            (updateProfileDTO.getNickname().length() < 1 || updateProfileDTO.getNickname().length() > 10)) {
            throw new RuntimeException("昵称长度必须在1-10个字符之间");
        }
        
        // 验证邮箱
        if (updateProfileDTO.getEmail() != null && 
            !EMAIL_PATTERN.matcher(updateProfileDTO.getEmail()).matches()) {
            throw new RuntimeException("邮箱格式错误");
        }
        
        // 验证性别
        if (updateProfileDTO.getGender() != null && 
            (updateProfileDTO.getGender() < 0 || updateProfileDTO.getGender() > 2)) {
            throw new RuntimeException("性别参数错误，必须为0-2之间的整数");
        }
    }

    @Override
    @Transactional
    public void sendResetCode(SendResetCodeDTO sendResetCodeDTO) {
        // 1. 验证参数
        if (sendResetCodeDTO.getUsername() == null || !USERNAME_PATTERN.matcher(sendResetCodeDTO.getUsername()).matches()) {
            throw new RuntimeException("用户名格式错误，必须为6-20位纯数字");
        }
        
        if (sendResetCodeDTO.getEmail() == null || !EMAIL_PATTERN.matcher(sendResetCodeDTO.getEmail()).matches()) {
            throw new RuntimeException("邮箱格式错误");
        }
        
        // 2. 检查用户是否存在
        Optional<User> userOpt = userMapper.findByUsername(sendResetCodeDTO.getUsername());
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }
        
        User user = userOpt.get();
        
        // 3. 检查邮箱是否匹配
        if (!user.getEmail().equals(sendResetCodeDTO.getEmail())) {
            throw new RuntimeException("邮箱与注册邮箱不匹配");
        }
        
        // 4. 生成6位数字验证码
        String code = generateVerificationCode();
        
        // 5. 保存验证码到数据库
        VerificationCode verificationCode = new VerificationCode();
        verificationCode.setUsername(user.getUsername());
        verificationCode.setCode(code);
        verificationCode.setType(VERIFICATION_TYPE_RESET_PASSWORD);
        verificationCode.setCreateTime(LocalDateTime.now());
        verificationCode.setExpireTime(LocalDateTime.now().plusMinutes(VERIFICATION_CODE_EXPIRE_MINUTES));
        verificationCode.setStatus(0); // 0-未使用
        
        verificationCodeMapper.insert(verificationCode);
        
        // 6. 发送验证码到邮箱
        emailService.sendResetPasswordEmail(user.getEmail(), user.getUsername(), code);
    }

    @Override
    @Transactional
    public void resetPassword(ResetPasswordDTO resetPasswordDTO) {
        // 1. 验证参数
        if (resetPasswordDTO.getUsername() == null || !USERNAME_PATTERN.matcher(resetPasswordDTO.getUsername()).matches()) {
            throw new RuntimeException("用户名格式错误，必须为6-20位纯数字");
        }
        
        if (resetPasswordDTO.getVerificationCode() == null || resetPasswordDTO.getVerificationCode().length() != 6) {
            throw new RuntimeException("验证码格式错误");
        }
        
        if (resetPasswordDTO.getNewPassword() == null || !PASSWORD_PATTERN.matcher(resetPasswordDTO.getNewPassword()).matches()) {
            throw new RuntimeException("新密码格式错误，必须为8-20位，且包含数字和字母");
        }
        
        if (resetPasswordDTO.getConfirmPassword() == null || !resetPasswordDTO.getConfirmPassword().equals(resetPasswordDTO.getNewPassword())) {
            throw new RuntimeException("两次输入的密码不一致");
        }
        
        // 2. 检查用户是否存在
        Optional<User> userOpt = userMapper.findByUsername(resetPasswordDTO.getUsername());
        if (userOpt.isEmpty()) {
            throw new RuntimeException("用户不存在");
        }
        
        User user = userOpt.get();
        
        // 3. 验证验证码
        Optional<VerificationCode> codeOpt = verificationCodeMapper.findLatestByUsernameAndType(
                resetPasswordDTO.getUsername(), VERIFICATION_TYPE_RESET_PASSWORD);
        
        if (codeOpt.isEmpty()) {
            throw new RuntimeException("验证码不存在或已过期");
        }
        
        VerificationCode verificationCode = codeOpt.get();
        
        if (!verificationCode.getCode().equals(resetPasswordDTO.getVerificationCode())) {
            throw new RuntimeException("验证码错误");
        }
        
        // 4. 更新验证码状态为已使用
        verificationCodeMapper.updateStatus(verificationCode.getId(), 1);
        
        // 5. 更新用户密码
        user.setPassword(passwordUtil.encode(resetPasswordDTO.getNewPassword()));
        user.setUpdateTime(LocalDateTime.now());
        userMapper.update(user);
        
        // 6. 使该用户的所有token失效
        tokenMapper.invalidate(user.getId());
    }
    
    /**
     * 生成6位数字验证码
     */
    private String generateVerificationCode() {
        Random random = new Random();
        int code = 100000 + random.nextInt(900000); // 生成100000-999999之间的随机数
        return String.valueOf(code);
    }
}